<?php
# ***** BEGIN LICENSE BLOCK *****
# This file is part of "myWiWall".
# Copyright (c) 2007-2008 CRP Henri Tudor and contributors.
# All rights reserved.
#
# "myWiWall" is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as published by
# the Free Software Foundation.
# 
# "myWiWall" is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with "myWiWall"; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# ***** END LICENSE BLOCK *****


/**
 * This proxy forwards ajax requests to external hosts
 *
 * @author Laurent Haan <laurent.haan@gmail.com>
 * @author Alain Vagner <alain.vagner@tudor.lu>
 * @author Jerome Bogaerts <jerome.bogaerts@tudor.lu>
 */
error_reporting(0);
define('IN_PROXY', true);
require_once (dirname(__FILE__) . '/../includes/common.php');

if (Auth::isAuth())
{
	$relayedHeaders 			= init();
	$forwardUrl 				= determineForwardUrl();
	$decomposedForwardUrl 		= decomposeForwardUrl($forwardUrl);
	$httpMethod 				= determineHttpMethod();
	
	try
	{
		$httpProxy = instantiateHttpProxy($decomposedForwardUrl, 
										  $relayedHeaders, 
										  $httpMethod);
		
		// Yeah we can proxify this request !
		$httpProxy->performRequest();
		$httpProxy->sendResponse();
	}
	catch (HttpProxyException $e)
	{
		renderError('500', 'Internal Server Error', $e->getMessage());
	}
}

// Bouuuh global functions oO !
function init()
{
	$relayedHeaders = array('Date', 
							'Content-type', 
							'Content-length', 
							'Vary', 
							'Connection', 
							'Content-encoding', 
							'Transfer-encoding');
	
	return $relayedHeaders;
}

function determineForwardUrl()
{
	if (!isset($_SERVER['HTTP_X_FORWARD_URL']))
		renderError(412, 'Precondition Failed', 'Unable to determine forward URL.');
	else
		$forwardUrl = $_SERVER['HTTP_X_FORWARD_URL'];
		
	return $forwardUrl;
}

function renderError($status, $statusLabel, $errorMessage)
{
	header("HTTP/1.1 " . $status . ' ' . $statusLabel, true);
	echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
	echo '<html>';
	echo '<head><title>Error ' . $status . ': ' . $statusLabel . '</title></head>';
	echo '<body><h1>Error ' . $status . ': ' . $statusLabel . '</h1>';
	echo '<p>' . $errorMessage . '</p></body>';
	echo '</html>';
	die();
}

function decomposeForwardUrl($forwardUrl)
{
	$decomposedForwardUrl = @parse_url($forwardUrl);
	
	if (!$decomposedForwardUrl || !isset($decomposedForwardUrl['scheme']) || 
		($decomposedForwardUrl['scheme'] != 'http' && $decomposedForwardUrl['scheme'] != 'https'))
	{
		renderError(412, 'Precondition Failed', 'Malformed forward URL.');
	}
	
	return $decomposedForwardUrl;
}

function determineHttpMethod()
{
	$httpMethod = (isset($_SERVER['HTTP_X_METHOD_EMULATION'])) ? strtoupper($_SERVER['HTTP_X_METHOD_EMULATION']) : strtoupper($_SERVER['REQUEST_METHOD']);
	return $httpMethod;
}

function instantiateHttpProxy($decomposedForwardUrl, $relayedHeaders, $httpMethod)
{
	$useHttps 		= ($decomposedForwardUrl['scheme'] == 'https');
	$host			= $decomposedForwardUrl['host'];
	$path			= (isset($decomposedForwardUrl['path'])) ? $decomposedForwardUrl['path'] : '/';
	$query			= (isset($decomposedForwardUrl['query'])) ? $decomposedForwardUrl['query'] : '';
	$proxyMethod 	= null;
	$port 			= null;
	$requestBody	= '';
	
	if (isset($decomposedForwardUrl['port']))
		$port = $decomposedForwardUrl['port'];
	else
		$port = ($useHttps) ? 443 : 80;

	switch($httpMethod)
	{
		case 'GET': 	$proxyMethod = HttpProxy::METHOD_GET; 		break;
		case 'POST': 	$proxyMethod = HttpProxy::METHOD_POST; 		break;
		case 'PUT': 	$proxyMethod = HttpProxy::METHOD_PUT; 		break;
		case 'DELETE': 	$proxyMethod = HttpProxy::METHOD_DELETE; 	break;
	}
	
	// HttpProxy object instanciation.
	$httpProxy = new HttpProxy($proxyMethod, $host, $port, $path, HttpProxy::VERSION_11, 4);
	$httpProxy->debug("C:\\logs\\MyWiWallProxy.log");
	
	// HTTPS ?
	$httpProxy->useHttps($useHttps);
	
	// Do we include a request body ?
	if ($httpMethod == 'POST' || $httpMethod == 'PUT')
		$httpProxy->setRequestBody(file_get_contents('php://input'));
		
	// We forward request parameters. If the query contains other parameters, we have
	// to append them to the Request URI.
	$httpProxy->setParameters($_GET);

	$params = explode('&', $query);
	
	if ($params)
	{
		foreach ($params as $p)
		{
			$a = explode('=', $p);
			
			// Take care of malform query strings ;)  !
			if (count($a) == 2)
				$httpProxy->setParameter($a[0], $a[1]);
		}	
	}
	
	// We set relayed response headers.
	$httpProxy->setRelayedHeaders($relayedHeaders);
	
	// Last, but not least (woooh ...), we set the headers that must be sent in
	// in the proxified Request. Actually, all of them but user-agent, host, and connection
	// that should be handled by the HttpProxy.
	foreach($_SERVER as $key => $value)
	{
		$headerFound = false;
	
		if (substr($key, 0, 4) == 'HTTP')
		{
			$fieldName = strtolower(str_replace('_', '-', substr($key, 5, strlen($key))));
			$fieldValue = $value;
			
			if ($fieldName != 'host' && $fieldName != 'connection' && $fieldName != 'keep-alive' && $fieldName != 'user-agent')
				$headerFound = true;
		}
		else if ($key == 'CONTENT_TYPE')
		{
			$headerFound = true;
		
			$fieldName = 'content-type';
			$fieldValue = $value;
		}
		
		if ($headerFound)
		{
			$httpProxy->setRequestHeader($fieldName, $fieldValue);
		}
	}
	
	
	// HTTP Basic Authentication management.
	if ((!isset($_SERVER['HTTP_X_WIDGET_AUTHENTICATION']) || $_SERVER['HTTP_X_WIDGET_AUTHENTICATION'] == 'disabled') && isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']))
		$httpProxy->setRequestHeader('Authorization', 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW']));
	
	// Widget authentication mechanism management.
	if (isset($_SERVER['HTTP_X_WIDGET_AUTHENTICATION']) && $_SERVER['HTTP_X_WIDGET_AUTHENTICATION'] == 'enabled')
	{
		$proof = Widgets::retrieveAuthenticationProof($_SERVER['HTTP_X_WIDGET_ID'], 'raw');
		$httpProxy->setRequestHeader('Authorization: Basic' . base64_encode($proof['identifier'] . ':' . $proof['signature']));
	}
	
	return $httpProxy;
}
?>